CON

  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000

  MAX_PWM_CHANNELS              = 32

var
' byte  duty_array[MAX_PWM_CHANNELS]

dat



pwm_channels  long      true'%0000_0000_0000_0000__0000_0001_0001_0111
duty_array    byte      0[MAX_PWM_CHANNELS]
              long

pub go | i

  cognew(@entry, @pwm_channels)

  duty_array[0]~

  i := 42

  duty_array[1] := 128
  duty_array[2] := 255
  
  repeat
    duty_array[0]++
    duty_array[0] //= $FF
    'duty_array[0] := (?i // $ff)
    waitcnt(cnt + clkfreq>>5)

dat

              org

entry         mov       w, par
              rdlong    pwm_chan, w
              add       w, #4
              mov       duty_array_addr, w
              or        dira, pwm_chan          'set the desired pins to output


init          mov       count, #0
              mov       w, ch0
              shl       w, #9
              'add       save_back, w
loop          mov       w, duty_array_addr
              add       w, count
              rdbyte    chan_duty, w            'load the appropriate channels duty value
              mov       w, ch0
              add       w, count        
              mov       pwm_work, w             'load the appropriate channels work value
              add       pwm_work, chan_duty     'do the calculation
              
              test      pwm_work, #$100 wz
              and       pwm_work, #$FF
save_back     mov       ch0, pwm_work
              mov       w, count
              shl       w, #9
              'add       save_back, w
              'mov      w, pwm_work
              mov       w, #1
              shl       w, count
              muxnz     outa, w
              'add       count, #1
              test      count, #$100 wz
        if_nz jmp       #init
              jmp       #loop
              
              
              
              'or       outa, pwm_chan
{
init          mov       pwm_chan, #0
loop          mov       w, duty_array_addr
              add       w, pwm_chan
              rdbyte    chan_duty, w
              mov       w, #ch0
              add       w, pwm_chan
              mov       pwm_work, #w
              add       pwm_work, chan_duty
              test      pwm_work, #$100 wz      'did we roll passed 8 bits?
              and       pwm_work, #$FF          'strip any bits beyond 8
              
              mov       w, #1
              shl       w, pwm_chan
              muxnz     outa, w
              add       pwm_chan, #1
              test      pwm_chan, #$20 wz       'does pwm_chan == 32?
        if_nz jmp       #init                   '  yes: reinitialize loop
              jmp       #loop                   '  no:  go to top of main loop

}         
{
              mov       count, #MAX_PWM_CHANNELS-1
              mov       w, count
              shl       w, #1                   'channel we are working on's base offset
              add       w, base_addr            'address is calced here
              mov       pwm_work, @w
              add       w, #1
              mov       pwm_duty, @w
              add       pwm_work, pwm_duty
              test      pwm_work, #$100 wz      'did we roll passed 8 bits?
              and       pwm_work, #$FF          'make sure that we are staying within 8 bits
              muxnz     outa, 
}              
              

duty_array_addr res     1

                                   
pwm_chan      res       1       'current pwm channel we are working on
w             res       1       'work accumulator
count         res       1       
'pwm_work     res       1
chan_duty     res       1


base_addr
'0x020
pwm_work      res       1
ch0           res       MAX_PWM_CHANNELS
'0x021
'ch1          res       1
'0x022
'ch2          res       1
'...

              fit
        